package com.fc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fc.dto.VehicleIncomeDTO;
import com.fc.entity.Expense;
import com.fc.entity.Logistics;
import com.fc.enums.ReviewStatus;
import com.fc.enums.TransportStatus;
import com.fc.exception.VehicleIncomeException;
import com.fc.mapper.ExpenseMapper;
import com.fc.mapper.LogisticsMapper;
import com.fc.service.VehicleIncomeService;
import com.fc.vo.VehicleIncomeDetailVO;
import com.fc.vo.VehicleIncomeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

@Service
public class VehicleIncomeServiceImpl implements VehicleIncomeService {


    @Autowired
    private LogisticsMapper logisticsMapper;

    @Autowired
    private ExpenseMapper expenseMapper;

    /**
     * 获取每个车的总收入、总支出和利润
     *
     * @param vehicleIncomePageQueryDTO
     * @return
     */
    @Override
    public List<VehicleIncomeVO> list(VehicleIncomeDTO vehicleIncomePageQueryDTO) {

        String vehiclePlate = vehicleIncomePageQueryDTO.getVehiclePlate();
        LocalDateTime start = vehicleIncomePageQueryDTO.getStart();
        LocalDateTime end = vehicleIncomePageQueryDTO.getEnd();
        List<Logistics> logisticsList = getLogisticsList(vehiclePlate, start, end);
        List<Expense> expenseList = getExpenseList(vehiclePlate, start, end);

        if (logisticsList.isEmpty() && expenseList.isEmpty()) {
            throw new VehicleIncomeException("无该车辆");
        }

        // 收集所有出现的车牌号（不去重）
        List<String> allVehiclePlates = getVehiclePlates(logisticsList, expenseList);

        // 使用 Set 去重只是为了生成唯一车牌用于遍历，但原始列表 still 不去重
        Set<String> uniquePlates = new HashSet<>(allVehiclePlates);
        // 按每个车牌号统计收入、支出、利润
        return getVehicleIncomeVOList(uniquePlates, logisticsList, expenseList);
    }

    /**
     * 获取车牌号
     *
     * @param logisticsList
     * @param expenseList
     * @return
     */
    private List<String> getVehiclePlates(List<Logistics> logisticsList, List<Expense> expenseList) {
        List<String> allVehiclePlates = new ArrayList<>();
        if (logisticsList != null) {
            allVehiclePlates.addAll(logisticsList.stream()
                    .map(Logistics::getVehiclePlate)
                    .filter(Objects::nonNull)
                    .toList());
        }
        if (expenseList != null) {
            allVehiclePlates.addAll(expenseList.stream()
                    .map(Expense::getVehiclePlate)
                    .filter(Objects::nonNull)
                    .toList());
        }
        return allVehiclePlates;
    }

    /**
     * 查询某个具体详细收支情况
     *
     * @param vehiclePlate
     * @return
     */
    @Override
    public VehicleIncomeDetailVO detail(String vehiclePlate) {
        List<Logistics> logisticsList = getLogisticsList(vehiclePlate, null, null);
        List<Expense> expenseList = getExpenseList(vehiclePlate, null, null);

        if (logisticsList.isEmpty() && expenseList.isEmpty()) {
            throw new VehicleIncomeException("无该车辆");
        }

        // 总收入
        BigDecimal totalIncome = logisticsList.stream()
                .map(Logistics::getPrice)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 总支出
        BigDecimal totalExpense = expenseList.stream()
                .map(Expense::getTotal)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        // 利润
        BigDecimal profit = totalIncome.subtract(totalExpense);

        // 分类支出统计
        VehicleIncomeDetailVO vehicleIncomeDetailVO = getVehicleIncomeDetailVO(expenseList);
        vehicleIncomeDetailVO.setTotalIncome(totalIncome);
        vehicleIncomeDetailVO.setTotalExpenses(totalExpense);
        vehicleIncomeDetailVO.setVehiclePlate(vehiclePlate);
        vehicleIncomeDetailVO.setProfit(profit);
        return vehicleIncomeDetailVO;
    }

    @Override
    public Set<String> listVehicle() {
        List<Logistics> logisticsList = logisticsMapper.selectList(null);
        List<Expense> expenseList = expenseMapper.selectList(null);
        // 收集所有出现的车牌号（不去重）
        List<String> allVehiclePlates = getVehiclePlates(logisticsList, expenseList);
        // 使用 Set 去重只是为了生成唯一车牌用于遍历，但原始列表 still 不去重
        return new HashSet<>(allVehiclePlates);
    }

    /**
     * 获取VehicleIncomeVO列表
     *
     * @param uniquePlates
     * @param logisticsList
     * @param expenseList
     * @return
     */
    private List<VehicleIncomeVO> getVehicleIncomeVOList(Set<String> uniquePlates, List<Logistics> logisticsList, List<Expense> expenseList) {
        return uniquePlates.stream()
                .map(vehicle -> {
                    // 计算该车牌的总收入
                    BigDecimal totalIncome = logisticsList.stream()
                            .filter(logistics -> vehicle.equals(logistics.getVehiclePlate()))
                            .map(Logistics::getPrice)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    // 计算该车牌的总支出
                    BigDecimal totalExpense = expenseList.stream()
                            .filter(expense -> vehicle.equals(expense.getVehiclePlate()))
                            .map(Expense::getTotal)
                            .filter(Objects::nonNull)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    // 利润
                    BigDecimal profit = totalIncome.subtract(totalExpense);
                    return new VehicleIncomeVO(vehicle, totalIncome, totalExpense, profit);
                })
                .toList();
    }


    /**
     * 获取VehicleIncomeDetailVO中的七个类别的总和
     *
     * @param expenseList
     * @return
     */
    private VehicleIncomeDetailVO getVehicleIncomeDetailVO(List<Expense> expenseList) {
        BigDecimal fuelTotal = expenseList.stream()
                .map(Expense::getFuel).filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal ureaTotal = expenseList.stream()
                .map(Expense::getUrea).filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal washingTotal = expenseList.stream()
                .map(Expense::getWashing).filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal repairTotal = expenseList.stream()
                .map(Expense::getRepair).filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal maintenanceTotal = expenseList.stream()
                .map(Expense::getMaintenance).filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal tireTotal = expenseList.stream()
                .map(Expense::getTire).filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal temporaryTotal = expenseList.stream()
                .map(Expense::getTemporary).filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

        return VehicleIncomeDetailVO.builder()
                .totalFuel(fuelTotal)
                .totalUrea(ureaTotal)
                .totalWashing(washingTotal)
                .totalRepair(repairTotal)
                .totalMaintenance(maintenanceTotal)
                .totalTire(tireTotal)
                .totalTemporary(temporaryTotal)
                .build();
    }

    /**
     * 获取Expense列表
     *
     * @param vehiclePlate
     * @param start
     * @param end
     * @return
     */

    private List<Expense> getExpenseList(String vehiclePlate, LocalDateTime start, LocalDateTime end) {
        //获取支出信息
        return expenseMapper.selectList(new LambdaQueryWrapper<Expense>()
                .eq(Expense::getStatus, ReviewStatus.APPROVE.getCode())
                .eq(vehiclePlate != null, Expense::getVehiclePlate, vehiclePlate)
                .between(start != null && end != null, Expense::getDate, start, end)
        );

    }

    /**
     * 获取Logistics列表
     *
     * @param vehiclePlate
     * @param start
     * @param end
     * @return
     */
    private List<Logistics> getLogisticsList(String vehiclePlate, LocalDateTime start, LocalDateTime end) {
        //获取收入信息
        return logisticsMapper.selectList(new LambdaQueryWrapper<Logistics>()
                .eq(Logistics::getStatus, TransportStatus.COMPLETED.getCode())
                .eq(vehiclePlate != null, Logistics::getVehiclePlate, vehiclePlate)
                .between(start != null && end != null, Logistics::getArrivalTime, start, end)
        );
    }

}
